package com.vincent.template.service.security.impl;

import com.google.common.collect.Sets;
import com.vincent.template.commons.base.VctTriple;
import com.vincent.template.service.security.UserAccessService;
import com.vincent.template.store.AuthUriStore;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author Vincent Wang
 * @date 2020/12/30 16:38
 */
@Service
public class UserAccessServiceImpl implements UserAccessService {

    private static final String ROLE_PREFIX = "ROLE_";

    @Autowired
    private AuthUriStore authUriStore;

    @Override
    public boolean isAccessible(HttpServletRequest request, Authentication authentication) {
        Set<Long> matchedUriIds = findMatchedUriIds(request);
        if (CollectionUtils.isEmpty(matchedUriIds)) {
            return true;
        }
        Map<String, Set<Long>> authUrisMap = authUriStore.findAuthUrisMap();
        if (org.springframework.util.CollectionUtils.isEmpty(authUrisMap)) {
            return false;
        }
        if (CollectionUtils.isEmpty(authentication.getAuthorities())) {
            return false;
        }
        return authentication.getAuthorities().stream().anyMatch(authority -> {
            String code = authority.getAuthority();
            if (code.startsWith(ROLE_PREFIX)) {
                return false;
            }
            return authUrisMap.containsKey(code) &&
                    CollectionUtils.containsAny(matchedUriIds, authUrisMap.get(code));
        });
    }

    /**
     * 根据request找到uri表中所有与之匹配的资源id
     * @param request
     * @return
     */
    private Set<Long> findMatchedUriIds(HttpServletRequest request) {
        List<VctTriple<Long, String, String>> uris = authUriStore.findUris();
        if (CollectionUtils.isEmpty(uris)) {
            return Sets.newHashSet();
        }
        // 如果uri表中的资源设置了请求方式，需要同时匹配pattern和请求方式
        // 如果没有设置请求方式，只匹配pattern，允许所有的请求方式
        return uris.stream().filter(uri -> {
            AntPathRequestMatcher matcher = StringUtils.isBlank(uri.getRight())
                    ? new AntPathRequestMatcher(uri.getMiddle())
                    : new AntPathRequestMatcher(uri.getMiddle(), uri.getRight());
            return matcher.matches(request);
        }).map(VctTriple::getLeft).collect(Collectors.toSet());
    }


}
